/** @file
	@brief Declarations related to #PrynEditorComponent. */
#ifndef PRYN_EDITOR_COMPONENT_H
#define PRYN_EDITOR_COMPONENT_H

#include <pryn/platform.h>

typedef struct PrynEditorComponent PrynEditorComponent; ///< A component on the board, attached to a #PrynComponent through a tag. This is normally returned from #prynEditorComponentFrom.
typedef PrynDList (PrynEditorComponent) PrynEditorComponentList; ///< List of editor components.

#include <pryn/editor/board.h>
#include <pryn/component.h>

#define PrynEditorComponentMargin 10 ///< The minimum margin in pixels between editor components on a board. This is doubled for the complete margin.

/** @defgroup PrynEditorComponent PrynEditorComponent C API
	@{
	@}
*/

#if __cplusplus
extern "C" {
#endif

/** @addtogroup PrynEditorComponent */
/** @{ */

PrynEditorImport (PrynResult, prynEditorComponentFrom, (PrynEditorComponent **editor, PrynEditorBoard *board, PrynComponent *component))
	/**< @brief Return the editor component for the component, creating it if necessary.

	@param[out] editor Receives the component or 0 on failure.
	@param board The board the component should be on. One component may be on multiple boards.
	@param component The component to find the editor data for.
	@returns #PrynResultSuccess or error code; see #PrynResult. */

PrynEditorImport (PrynResult, prynEditorComponentMove, (PrynEditorComponent *component, int x, int y))
	/**< @brief Move the editor component to a new position.
	
	This will cause the pathing to be dirtied, and any altered areas of the screen to be redrawn, if the position is not the same.

	@param component The component to move.
	@param x The horizontal coordinate of the left edge of the new position, relative to the scroll point of the board.
	@param y The vertical coordinate of the top edge of the new position, relative to the scroll point of the board.
	@returns #PrynResultSuccess on success, #PrynResultDone if the position was the same. Errors may be returned on failure; see #PrynResult. */

PrynEditorImport (PrynResult, prynEditorComponentDirty, (PrynEditorComponent *component))
	/**< @brief Cause the control to be redrawn for this component.

	This redraws the component and all connections.

	@param component The component to redraw.
	@returns #PrynResultSuccess on success, or an error code; see #PrynResult. */

PrynEditorImport (PrynResult, prynEditorComponentDirtyConnections, (PrynEditorComponent *component))
	/**< @brief Cause all connections to the component to be redrawn.

	@param component The component to redraw the connections of.
	@returns #PrynResultSuccess on success, or an error code; see #PrynResult. */

PrynEditorImport (PrynResult, prynEditorComponentDirtyOutputConnections, (PrynEditorComponent *component))
	/**< @brief Cause all output connections (connections from the output pins of the component) to be redrawn.
	
	@param component The component to redraw the output connections of.
	@returns #PrynResultSuccess on success, or an error code; see #PrynResult. */

PrynEditorImport (bool, prynEditorComponentEachOutputPin, (PrynEditorComponent *component, bool (*each) (PrynEditorComponent *component, PrynPin *pin, int x, int y, void *data), void *data))
	/**< @brief Iterate over all the output pins in the component.

	@param component The component to iterate over.
	@param each The function to call on each pin. It's passed the component, pin, the top-left position of the pin, and the @e data parameter. If this returns @b false, iteration stops.
	@param data Data parameter passed to @e each.
	@returns @b true if @e each always returns @b true; @b false otherwise or if there's an error. */

PrynEditorImport (bool, prynEditorComponentEachInputPin, (PrynEditorComponent *component, bool (*each) (PrynEditorComponent *component, PrynPin *pin, int x, int y, void *data), void *data))
	/**< @brief Iterate over all the input pins in the component.

	@param component The component to iterate over.
	@param each The function to call on each pin. It's passed the component, pin, the top-left position of the pin, and the @e data parameter. If this returns @b false, iteration stops.
	@param data Data parameter passed to @e each.
	@returns @b true if @e each always returns @b true; @b false otherwise or if there's an error. */

PrynEditorImport (bool, prynEditorComponentEachPin, (PrynEditorComponent *component, bool (*each) (PrynEditorComponent *component, PrynPin *pin, int x, int y, void *data), void *data))
	/**< @brief Iterate over all the pins in the component.

	@param component The component to iterate over.
	@param each The function to call on each pin. It's passed the component, pin, the top-left position of the pin, and the @e data parameter. If this returns @b false, iteration stops.
	@param data Data parameter passed to @e each.
	@returns @b true if @e each always returns @b true; @b false otherwise or if there's an error. */

PrynEditorImport (PrynResult, prynEditorComponentUpdatePins, (PrynEditorComponent *component))
	/**< @brief Update the editor pin locations.

	This is called internally when a component adds pins or is moved.

	@param component The component to update the pins of.
	@returns #PrynResultSuccess on success, or an error code; see #PrynResult. */

/** @} */ // (addtogroup PrynEditorComponent)

#if __cplusplus
}
#endif

#ifdef PrynEditorInternalStructs
/** A component on the board, attached to a #PrynComponent through a tag. This is normally returned from #prynEditorComponentFrom.

	@ingroup PrynEditorBoard */
struct PrynEditorComponent
{
#ifdef PrynEditorInternal
/** @name Internal fields
	These fields are not normally visible to clients, and it is recommended not to use them to maximise binary compatibility. To make them available, define #PrynEditorInternal.
	@{ */
	PrynEditorBoard *board; ///< Link back to the board.
	PrynEditorComponent *previous; ///< Previous component in the chain.
	PrynEditorComponent *next; ///< Next component in the chain.
	PrynComponent *component; ///< The component.
	int x; ///< Horizontal offset of the left edge of the component in pixels.
	int y; ///< Vertical offset of the top edge of the component in pixels.
	int w; ///< Width of the component area in pixels.
	int h; ///< Height of the component area in pixels.
/** @} */
#endif /* PrynEditorInternal */

#if __cplusplus
	static inline PrynEditorComponent *From (PrynEditorBoard *board, PrynComponent *component) { PrynEditorComponent *result; prynEditorComponentFrom (&result, board, component); return result; }
		/**< @brief Return the editor component for the component, creating it if necessary.

		@param board The board the component should be on. One component may be on multiple boards.
		@param component The component to find the editor data for.
		@returns The editor component on success. */

	inline bool move (int x, int y) { return prynEditorComponentMove (this, x, y) == PrynResultSuccess; }
		/**< @brief Move the editor component to a new position.
		
		This will cause the pathing to be dirtied, and any altered areas of the screen to be redrawn, if the position is not the same.

		@param x The horizontal coordinate of the left edge of the new position, relative to the scroll point of the board.
		@param y The vertical coordinate of the top edge of the new position, relative to the scroll point of the board.
		@returns @b true if this is a new position, @b false if it's the same as the old position. */

	inline void dirty () { prynEditorComponentDirty (this); }
		/**< @brief Cause the control to be redrawn for this component.

		This redraws the component and all connections. */

	inline void dirtyConnections () { prynEditorComponentDirtyConnections (this); }
		/**< @brief Cause all connections to the component to be redrawn. */

	inline void dirtyOutputConnections () { prynEditorComponentDirtyOutputConnections (this); }
		/**< @brief Cause all output connections (connections from the output pins of the component) to be redrawn. */

	inline void updatePinLocations () { prynEditorComponentUpdatePins (this); }
		/**< @brief Update the editor pin locations.

		This is called internally when a component adds pins or is moved.

		@returns #PrynResultSuccess on success, or an error code; see #PrynResult. */

	inline bool eachOutputPin (bool (*each) (PrynEditorComponent *component, PrynPin *pin, int x, int y, void *data), void *data) { return prynEditorComponentEachOutputPin (this, each, data); }
		/**< @brief Iterate over all the output pins in the component.

		@param each The function to call on each pin. It's passed the component, pin, the top-left position of the pin, and the @e data parameter. If this returns @b false, iteration stops.
		@param data Data parameter passed to @e each.
		@returns @b true if @e each always returns @b true; @b false otherwise or if there's an error. */

	inline bool eachInputPin (bool (*each) (PrynEditorComponent *component, PrynPin *pin, int x, int y, void *data), void *data) { return prynEditorComponentEachInputPin (this, each, data); }
		/**< @brief Iterate over all the input pins in the component.

		@param each The function to call on each pin. It's passed the component, pin, the top-left position of the pin, and the @e data parameter. If this returns @b false, iteration stops.
		@param data Data parameter passed to @e each.
		@returns @b true if @e each always returns @b true; @b false otherwise or if there's an error. */

	inline bool eachPin (bool (*each) (PrynEditorComponent *component, PrynPin *pin, int x, int y, void *data), void *data) { return prynEditorComponentEachPin (this, each, data); }
		/**< @brief Iterate over all the pins in the component.

		@param each The function to call on each pin. It's passed the component, pin, the top-left position of the pin, and the @e data parameter. If this returns @b false, iteration stops.
		@param data Data parameter passed to @e each.
		@returns @b true if @e each always returns @b true; @b false otherwise or if there's an error. */

#endif /* __cplusplus */
};
#endif /* PrynEditorStructs */

#endif /* PRYN_EDITOR_COMPONENT_H */
